๊ฒฌ๊ณ ํ๊ณ ํ์ฅ ๊ฐ๋ฅํ ์น ์ปดํฌ๋ํธ ์ธํ๋ผ๋ฅผ ๊ตฌ์ถํ์ธ์. ์ด ๊ฐ์ด๋์์๋ ๊ธ๋ก๋ฒ ์น ๊ฐ๋ฐ์ ์ํ ๋์์ธ ์์น, ๋๊ตฌ, ๋ชจ๋ฒ ์ฌ๋ก ๋ฐ ๊ณ ๊ธ ๊ธฐ์ ์ ๋ค๋ฃน๋๋ค.
์น ์ปดํฌ๋ํธ ์ธํ๋ผ: ์ข ํฉ์ ์ธ ๊ตฌํ ๊ฐ์ด๋
์น ์ปดํฌ๋ํธ๋ ํ๋์ ์ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ UI ์์๋ฅผ ๋ง๋๋ ๊ฐ๋ ฅํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ํนํ ์ ์ธ๊ณ์ ๋ถ์ฐ๋ ๋๊ท๋ชจ ํ์์ ์์ ํ ๋, ํ์ฅ์ฑ, ์ ์ง๋ณด์์ฑ, ์ผ๊ด์ฑ์ ์ํด์๋ ์น ์ปดํฌ๋ํธ๋ฅผ ์ค์ฌ์ผ๋ก ๊ฒฌ๊ณ ํ ์ธํ๋ผ๋ฅผ ๊ตฌ์ถํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ด ๊ฐ์ด๋๋ ๊ฒฌ๊ณ ํ ์น ์ปดํฌ๋ํธ ์ธํ๋ผ๋ฅผ ์ค๊ณ, ๊ตฌํ ๋ฐ ๋ฐฐํฌํ๋ ๋ฐฉ๋ฒ์ ๋ํ ํฌ๊ด์ ์ธ ๊ฐ์๋ฅผ ์ ๊ณตํฉ๋๋ค.
ํต์ฌ ๊ฐ๋ ์ดํดํ๊ธฐ
๊ตฌํ์ ์์, ์น ์ปดํฌ๋ํธ์ ๊ธฐ๋ณธ ๊ตฌ์ฑ ์์๋ฅผ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค:
- ์ปค์คํ ์๋ฆฌ๋จผํธ(Custom Elements): ์์ฒด HTML ํ๊ทธ๋ฅผ ๊ด๋ จ ์๋ฐ์คํฌ๋ฆฝํธ ๋์๊ณผ ํจ๊ป ์ ์ํ ์ ์์ต๋๋ค.
- ์๋ DOM(Shadow DOM): ์บก์ํ๋ฅผ ์ ๊ณตํ์ฌ ์คํ์ผ๊ณผ ์คํฌ๋ฆฝํธ๊ฐ ์ปดํฌ๋ํธ ์ํ์ผ๋ก ์ ์ถ๋๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค.
- HTML ํ ํ๋ฆฟ(HTML Templates): ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ HTML ๊ตฌ์กฐ๋ฅผ ์ ์ํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
- ES ๋ชจ๋(ES Modules): ๋ชจ๋์ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ๋ฐ ๋ฐ ์์กด์ฑ ๊ด๋ฆฌ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
์น ์ปดํฌ๋ํธ ์ธํ๋ผ๋ฅผ ์ํ ๋์์ธ ์์น
์ ์ค๊ณ๋ ์น ์ปดํฌ๋ํธ ์ธํ๋ผ๋ ๋ค์ ์์น์ ์ค์ํด์ผ ํฉ๋๋ค:
- ์ฌ์ฌ์ฉ์ฑ: ์ปดํฌ๋ํธ๋ ๋ค์ํ ํ๋ก์ ํธ์ ์ปจํ ์คํธ์์ ์ฌ์ฌ์ฉํ ์ ์๋๋ก ์ค๊ณ๋์ด์ผ ํฉ๋๋ค.
- ์บก์ํ: ์๋ DOM์ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ๊ฐ ๊ฒฉ๋ฆฌ๋๊ณ ์๋ก ๊ฐ์ญํ์ง ์๋๋ก ํด์ผ ํฉ๋๋ค.
- ์กฐํฉ์ฑ: ์ปดํฌ๋ํธ๋ ๋ ๋ณต์กํ UI ์์๋ฅผ ๋ง๋ค๊ธฐ ์ํด ์ฝ๊ฒ ํจ๊ป ์กฐํฉ๋ ์ ์๋๋ก ์ค๊ณ๋์ด์ผ ํฉ๋๋ค.
- ์ ๊ทผ์ฑ: ์ปดํฌ๋ํธ๋ WCAG ๊ฐ์ด๋๋ผ์ธ์ ๋ฐ๋ผ ์ฅ์ ๋ฅผ ๊ฐ์ง ์ฌ์ฉ์๋ ์ ๊ทผํ ์ ์์ด์ผ ํฉ๋๋ค.
- ์ ์ง๋ณด์์ฑ: ์ธํ๋ผ๋ ์ ์ง๋ณด์ํ๊ณ ์ ๋ฐ์ดํธํ๊ธฐ ์ฌ์์ผ ํฉ๋๋ค.
- ํ ์คํธ ์ฉ์ด์ฑ: ์ปดํฌ๋ํธ๋ ์๋ํ๋ ํ ์คํธ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๊ฒ ํ ์คํธํ ์ ์์ด์ผ ํฉ๋๋ค.
- ์ฑ๋ฅ: ์ปดํฌ๋ํธ๋ ์ฑ๋ฅ์ด ๋ฐ์ด๋๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๋ฐ์ ์ธ ์ฑ๋ฅ์ ์ํฅ์ ๋ฏธ์น์ง ์๋๋ก ์ค๊ณ๋์ด์ผ ํฉ๋๋ค.
- ๊ตญ์ ํ ๋ฐ ํ์งํ (i18n/l10n): ์ปดํฌ๋ํธ๋ ์ฌ๋ฌ ์ธ์ด์ ์ง์ญ์ ์ง์ํ๋๋ก ์ค๊ณ๋์ด์ผ ํฉ๋๋ค. ๊ตญ์ ํ๋ฅผ ์ํด
i18next์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ธ๋ผ์ฐ์ API ์ฌ์ฉ์ ๊ณ ๋ คํ์ธ์. ์๋ฅผ ๋ค์ด, ๋ ์ง ํ์์ ์ฌ์ฉ์์ ๋ก์ผ์ผ์ ์กด์คํด์ผ ํฉ๋๋ค:
const dateFormatter = new Intl.DateTimeFormat(userLocale, options);
const formattedDate = dateFormatter.format(date);
๊ฐ๋ฐ ํ๊ฒฝ ์ค์ ํ๊ธฐ
๊ฒฌ๊ณ ํ ๊ฐ๋ฐ ํ๊ฒฝ์ ์น ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ์ถํ๊ณ ์ ์งํ๋ ๋ฐ ์ค์ํฉ๋๋ค. ๊ถ์ฅ๋๋ ์ค์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- Node.js์ npm (๋๋ yarn/pnpm): ์์กด์ฑ ๊ด๋ฆฌ ๋ฐ ๋น๋ ์คํฌ๋ฆฝํธ ์คํ์ ์ํจ.
- ์ฝ๋ ์๋ํฐ (VS Code, Sublime Text ๋ฑ): ์๋ฐ์คํฌ๋ฆฝํธ, HTML, CSS๋ฅผ ์ง์ํ๋ ์๋ํฐ.
- ๋น๋ ๋๊ตฌ (Webpack, Rollup, Parcel): ์ฝ๋ ๋ฒ๋ค๋ง ๋ฐ ์ต์ ํ๋ฅผ ์ํจ.
- ํ ์คํ ํ๋ ์์ํฌ (Jest, Mocha, Chai): ๋จ์ ํ ์คํธ ์์ฑ ๋ฐ ์คํ์ ์ํจ.
- ๋ฆฐํฐ ๋ฐ ํฌ๋งทํฐ (ESLint, Prettier): ์ฝ๋ ์คํ์ผ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก ๊ฐ์ ๋ฅผ ์ํจ.
create-web-component๋ open-wc์ ์์ฑ๊ธฐ์ ๊ฐ์ ํ๋ก์ ํธ ์ค์บํด๋ฉ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ํ์ํ ๋ชจ๋ ๋๊ตฌ๊ฐ ๊ตฌ์ฑ๋ ์๋ก์ด ์น ์ปดํฌ๋ํธ ํ๋ก์ ํธ๋ฅผ ์ ์ํ๊ฒ ์ค์ ํ๋ ๊ฒ์ ๊ณ ๋ คํด ๋ณด์ธ์.
๊ธฐ๋ณธ ์น ์ปดํฌ๋ํธ ๊ตฌํํ๊ธฐ
์ธ์ฌ ๋ฉ์์ง๋ฅผ ํ์ํ๋ ๊ฐ๋จํ ์น ์ปดํฌ๋ํธ ์์ ๋ก ์์ํ๊ฒ ์ต๋๋ค:
// greeting-component.js
class GreetingComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
}
static get observedAttributes() {
return ['name'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'name' && oldValue !== newValue) {
this.render();
}
}
render() {
this.shadowRoot.innerHTML = `
Hello, ${this.name || 'World'}!
`;
}
get name() {
return this.getAttribute('name');
}
set name(value) {
this.setAttribute('name', value);
}
}
customElements.define('greeting-component', GreetingComponent);
์ด ์ฝ๋๋ greeting-component๋ผ๋ ์ปค์คํ
์๋ฆฌ๋จผํธ๋ฅผ ์ ์ํฉ๋๋ค. ์๋ DOM์ ์ฌ์ฉํ์ฌ ๋ด๋ถ ๊ตฌ์กฐ์ ์คํ์ผ์ ์บก์ํํฉ๋๋ค. name ์์ฑ์ ์ฌ์ฉํ๋ฉด ์ธ์ฌ ๋ฉ์์ง๋ฅผ ์ฌ์ฉ์ ์ ์ํ ์ ์์ต๋๋ค. ์ด ์ปดํฌ๋ํธ๋ฅผ HTML์์ ์ฌ์ฉํ๋ ค๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ ํ์ผ์ ํฌํจํ๊ณ ๋ค์ ํ๊ทธ๋ฅผ ์ถ๊ฐํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค:
์ปดํฌ๋ํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ตฌ์ถํ๊ธฐ
๋๊ท๋ชจ ํ๋ก์ ํธ์ ๊ฒฝ์ฐ, ์น ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๊ตฌ์ฑํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ด๋ ์ผ๊ด์ฑ์ ์ด์งํ๊ณ ์ฝ๋ ์ค๋ณต์ ์ค์ฌ์ค๋๋ค. ์ปดํฌ๋ํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ตฌ์ถํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ: ์ปดํฌ๋ํธ๋ฅผ ๊ธฐ๋ฅ์ด๋ ์นดํ ๊ณ ๋ฆฌ์ ๋ฐ๋ผ ๋ ผ๋ฆฌ์ ์ธ ํด๋๋ก ๊ตฌ์ฑํ์ธ์.
- ์ด๋ฆ ์ง์ ๊ท์น: ์ปดํฌ๋ํธ์ ํ์ผ์ ์ผ๊ด๋ ์ด๋ฆ ์ง์ ๊ท์น์ ์ฌ์ฉํ์ธ์.
- ๋ฌธ์ํ: ์ฌ์ฉ ์์ , ์์ฑ, ์ด๋ฒคํธ๋ฅผ ํฌํจํ์ฌ ๊ฐ ์ปดํฌ๋ํธ์ ๋ํ ๋ช ํํ๊ณ ํฌ๊ด์ ์ธ ๋ฌธ์๋ฅผ ์ ๊ณตํ์ธ์. Storybook๊ณผ ๊ฐ์ ๋๊ตฌ๊ฐ ๋งค์ฐ ์ ์ฉํ ์ ์์ต๋๋ค.
- ๋ฒ์ ๊ด๋ฆฌ: ์๋งจํฑ ๋ฒ์ ๋์ ์ฌ์ฉํ์ฌ ๋ณ๊ฒฝ ์ฌํญ์ ์ถ์ ํ๊ณ ํ์ ํธํ์ฑ์ ๋ณด์ฅํ์ธ์.
- ๊ฒ์: ์ปดํฌ๋ํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ npm์ด๋ GitHub Packages์ ๊ฐ์ ํจํค์ง ๋ ์ง์คํธ๋ฆฌ์ ๊ฒ์ํ์ฌ ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค์ด ์ฝ๊ฒ ์ปดํฌ๋ํธ๋ฅผ ์ค์นํ๊ณ ์ฌ์ฉํ ์ ์๋๋ก ํ์ธ์.
๋๊ตฌ ๋ฐ ์๋ํ
์น ์ปดํฌ๋ํธ์ ๋น๋, ํ ์คํธ, ๊ฒ์์ ๊ฐ์ ์์ ์ ์๋ํํ๋ฉด ๊ฐ๋ฐ ์ํฌํ๋ก์ฐ๋ฅผ ํฌ๊ฒ ๊ฐ์ ํ ์ ์์ต๋๋ค. ๊ณ ๋ คํด ๋ณผ ๋งํ ๋ช ๊ฐ์ง ๋๊ตฌ์ ๊ธฐ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๋น๋ ๋๊ตฌ (Webpack, Rollup, Parcel): ๋น๋ ๋๊ตฌ๋ฅผ ๊ตฌ์ฑํ์ฌ ์ปดํฌ๋ํธ๋ฅผ ์ต์ ํ๋ ์๋ฐ์คํฌ๋ฆฝํธ ํ์ผ๋ก ๋ฒ๋ค๋งํ์ธ์.
- ํ ์คํ ํ๋ ์์ํฌ (Jest, Mocha, Chai): ๋จ์ ํ ์คํธ๋ฅผ ์์ฑํ์ฌ ์ปดํฌ๋ํธ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํ์ธ์.
- ์ง์์ ํตํฉ/์ง์์ ๋ฐฐํฌ (CI/CD): CI/CD ํ์ดํ๋ผ์ธ์ ์ค์ ํ์ฌ ์ฝ๋๋ฒ ์ด์ค์ ๋ณ๊ฒฝ์ด ์์ ๋๋ง๋ค ์ปดํฌ๋ํธ๋ฅผ ์๋์ผ๋ก ๋น๋, ํ ์คํธ, ๋ฐฐํฌํ์ธ์. ์ธ๊ธฐ ์๋ CI/CD ํ๋ซํผ์ผ๋ก๋ GitHub Actions, GitLab CI, Jenkins๊ฐ ์์ต๋๋ค.
- ์ ์ ๋ถ์ (ESLint, Prettier): ์ ์ ๋ถ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋ ์คํ์ผ๊ณผ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ฐ์ ํ์ธ์. ์ด ๋๊ตฌ๋ค์ CI/CD ํ์ดํ๋ผ์ธ์ ํตํฉํ์ฌ ์ฝ๋์ ์ค๋ฅ์ ๋น์ผ๊ด์ฑ์ ์๋์ผ๋ก ํ์ธํ์ธ์.
- ๋ฌธ์ ์์ฑ๊ธฐ (Storybook, JSDoc): ๋ฌธ์ ์์ฑ๊ธฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋์ ์ฃผ์์ ๊ธฐ๋ฐ์ผ๋ก ์ปดํฌ๋ํธ ๋ฌธ์๋ฅผ ์๋์ผ๋ก ์์ฑํ์ธ์.
๊ณ ๊ธ ๊ธฐ์
๊ฒฌ๊ณ ํ ๊ธฐ๋ฐ์ ๋ง๋ จํ๋ค๋ฉด, ์น ์ปดํฌ๋ํธ ์ธํ๋ผ๋ฅผ ๋์ฑ ํฅ์์ํค๊ธฐ ์ํ ๊ณ ๊ธ ๊ธฐ์ ์ ํ์ํ ์ ์์ต๋๋ค:
- ์ํ ๊ด๋ฆฌ: Redux๋ MobX์ ๊ฐ์ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ณต์กํ ์ปดํฌ๋ํธ ์ํ๋ฅผ ๊ด๋ฆฌํ์ธ์.
- ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ: ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋ ๋ ์ปดํฌ๋ํธ ์์ฑ์ด ์๋์ผ๋ก ์ ๋ฐ์ดํธ๋๋๋ก ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ๊ตฌํํ์ธ์. lit-html๊ณผ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํจ์จ์ ์ธ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค.
- ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง (SSR): SEO ๋ฐ ์ด๊ธฐ ํ์ด์ง ๋ก๋ ์๊ฐ์ ๊ฐ์ ํ๊ธฐ ์ํด ์๋ฒ์์ ์น ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ์ธ์.
- ๋ง์ดํฌ๋ก ํ๋ก ํธ์๋: ์น ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ง์ดํฌ๋ก ํ๋ก ํธ์๋๋ฅผ ๊ตฌ์ถํ๋ฉด, ๋๊ท๋ชจ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ ์๊ณ ๋ ๋ฆฝ์ ์ผ๋ก ๋ฐฐํฌ ๊ฐ๋ฅํ ๋จ์๋ก ๋ถํ ํ ์ ์์ต๋๋ค.
- ์ ๊ทผ์ฑ (ARIA): ARIA ์์ฑ์ ๊ตฌํํ์ฌ ์ฅ์ ๋ฅผ ๊ฐ์ง ์ฌ์ฉ์๋ฅผ ์ํ ์ปดํฌ๋ํธ์ ์ ๊ทผ์ฑ์ ํฅ์์ํค์ธ์.
ํฌ๋ก์ค ๋ธ๋ผ์ฐ์ ํธํ์ฑ
์น ์ปดํฌ๋ํธ๋ ์ต์ ๋ธ๋ผ์ฐ์ ์์ ๋๋ฆฌ ์ง์๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ๊ตฌํ ๋ธ๋ผ์ฐ์ ๋ ํ์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ธฐ ์ํด ํด๋ฆฌํ(polyfill)์ด ํ์ํ ์ ์์ต๋๋ค. @webcomponents/webcomponentsjs์ ๊ฐ์ ํด๋ฆฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ํฌ๋ก์ค ๋ธ๋ผ์ฐ์ ํธํ์ฑ์ ๋ณด์ฅํ์ธ์. Polyfill.io์ ๊ฐ์ ์๋น์ค๋ฅผ ์ฌ์ฉํ์ฌ ํ์ํ ๋ธ๋ผ์ฐ์ ์๋ง ํด๋ฆฌํ์ ์ ๊ณตํจ์ผ๋ก์จ ์ต์ ๋ธ๋ผ์ฐ์ ์ ์ฑ๋ฅ์ ์ต์ ํํ๋ ๊ฒ์ ๊ณ ๋ คํด ๋ณด์ธ์.
๋ณด์ ๊ณ ๋ ค์ฌํญ
์น ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ์ถํ ๋ ์ ์ฌ์ ์ธ ๋ณด์ ์ทจ์ฝ์ ์ ์ ์ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค:
- ํฌ๋ก์ค ์ฌ์ดํธ ์คํฌ๋ฆฝํ (XSS): XSS ๊ณต๊ฒฉ์ ๋ฐฉ์งํ๊ธฐ ์ํด ์ฌ์ฉ์ ์ ๋ ฅ์ ์ด๊ท (sanitize)ํ์ธ์. ํ ํ๋ฆฟ ๋ฆฌํฐ๋ด์ ์ ์ ํ ์ด์ค์ผ์ดํ ์ฒ๋ฆฌํ์ง ์์ผ๋ฉด ์ทจ์ฝ์ ์ ์ ๋ฐํ ์ ์์ผ๋ฏ๋ก ์ฃผ์ํด์ ์ฌ์ฉํ์ธ์.
- ์์กด์ฑ ์ทจ์ฝ์ : ๋ณด์ ์ทจ์ฝ์ ์ ํด๊ฒฐํ๊ธฐ ์ํด ์ ๊ธฐ์ ์ผ๋ก ์์กด์ฑ์ ์ ๋ฐ์ดํธํ์ธ์. npm audit์ด๋ Snyk๊ณผ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ์์กด์ฑ์ ์ทจ์ฝ์ ์ ์๋ณํ๊ณ ์์ ํ์ธ์.
- ์๋ DOM ๊ฒฉ๋ฆฌ: ์๋ DOM์ ์บก์ํ๋ฅผ ์ ๊ณตํ์ง๋ง ์๋ฒฝํ ๋ณด์ ์กฐ์น๋ ์๋๋๋ค. ์ปดํฌ๋ํธ ๋ด์์ ์ธ๋ถ ์ฝ๋ ๋ฐ ๋ฐ์ดํฐ์ ์ํธ ์์ฉํ ๋ ์ฃผ์ํ์ธ์.
ํ์ ๋ฐ ๊ฑฐ๋ฒ๋์ค
๋๊ท๋ชจ ํ์ ๊ฒฝ์ฐ, ์ผ๊ด์ฑ๊ณผ ํ์ง์ ์ ์งํ๊ธฐ ์ํด ๋ช ํํ ๊ฐ์ด๋๋ผ์ธ๊ณผ ๊ฑฐ๋ฒ๋์ค๋ฅผ ์๋ฆฝํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ค์ ์ฌํญ์ ๊ณ ๋ คํ์ธ์:
- ์ฝ๋ ์คํ์ผ ๊ฐ์ด๋: ๋ช ํํ ์ฝ๋ ์คํ์ผ ๊ฐ์ด๋๋ผ์ธ์ ์ ์ํ๊ณ ๋ฆฐํฐ์ ํฌ๋งทํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฅผ ๊ฐ์ ํ์ธ์.
- ์ปดํฌ๋ํธ ์ด๋ฆ ์ง์ ๊ท์น: ์ปดํฌ๋ํธ์ ์์ฑ์ ๋ํ ์ผ๊ด๋ ์ด๋ฆ ์ง์ ๊ท์น์ ์๋ฆฝํ์ธ์.
- ์ปดํฌ๋ํธ ๊ฒํ ํ๋ก์ธ์ค: ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ ์๊ตฌ๋๋ ํ์ค์ ์ถฉ์กฑํ๋์ง ํ์ธํ๊ธฐ ์ํด ์ฝ๋ ๊ฒํ ํ๋ก์ธ์ค๋ฅผ ๊ตฌํํ์ธ์.
- ๋ฌธ์ํ ํ์ค: ๋ช ํํ ๋ฌธ์ํ ํ์ค์ ์ ์ํ๊ณ ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ ์ ๋๋ก ๋ฌธ์ํ๋์๋์ง ํ์ธํ์ธ์.
- ์ค์ ์ง์ค์ ์ปดํฌ๋ํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ: ์ฌ์ฌ์ฉ๊ณผ ์ผ๊ด์ฑ์ ์ด์งํ๊ธฐ ์ํด ์ค์ ์ง์ค์ ์ปดํฌ๋ํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ์งํ์ธ์.
Bit๊ณผ ๊ฐ์ ๋๊ตฌ๋ ์ฌ๋ฌ ํ๋ก์ ํธ์ ํ ๊ฐ์ ์น ์ปดํฌ๋ํธ๋ฅผ ๊ด๋ฆฌํ๊ณ ๊ณต์ ํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
์์ : ๋ค๊ตญ์ด ์น ์ปดํฌ๋ํธ ๊ตฌ์ถํ๊ธฐ
์ฌ๋ฌ ์ธ์ด๋ก ํ
์คํธ๋ฅผ ํ์ํ๋ ๊ฐ๋จํ ์น ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. ์ด ์์ ์์๋ ๊ตญ์ ํ๋ฅผ ์ํด i18next ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
// i18n-component.js
import i18next from 'i18next';
class I18nComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
async connectedCallback() {
await i18next.init({
lng: 'en',
resources: {
en: {
translation: {
greeting: 'Hello, World!'
}
},
fr: {
translation: {
greeting: 'Bonjour le monde !'
}
},
es: {
translation: {
greeting: 'ยกHola Mundo!'
}
}
}
});
this.render();
}
static get observedAttributes() {
return ['language'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'language' && oldValue !== newValue) {
i18next.changeLanguage(newValue);
this.render();
}
}
render() {
this.shadowRoot.innerHTML = `
${i18next.t('greeting')}
`;
}
get language() {
return this.getAttribute('language');
}
set language(value) {
this.setAttribute('language', value);
}
}
customElements.define('i18n-component', I18nComponent);
์ด ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ ํ์ผ์ ํฌํจํ๊ณ ๋ค์ ํ๊ทธ๋ฅผ ์ถ๊ฐํ์ธ์:
๊ฒฐ๋ก
๊ฒฌ๊ณ ํ ์น ์ปดํฌ๋ํธ ์ธํ๋ผ๋ฅผ ๊ตฌ์ถํ๋ ค๋ฉด ์ ์คํ ๊ณํ, ์ค๊ณ ๋ฐ ๊ตฌํ์ด ํ์ํฉ๋๋ค. ์ด ๊ฐ์ด๋์์ ์ค๋ช ํ ์์น๊ณผ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๋ฉด ์กฐ์ง์ ์ํ ํ์ฅ ๊ฐ๋ฅํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ๋ฉฐ ์ผ๊ด๋ ์น ์ปดํฌ๋ํธ ์ํ๊ณ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ์ฌ์ฌ์ฉ์ฑ, ์บก์ํ, ์ ๊ทผ์ฑ ๋ฐ ์ฑ๋ฅ์ ์ฐ์ ์ํ๋ ๊ฒ์ ์์ง ๋ง์ธ์. ๋๊ตฌ์ ์๋ํ๋ฅผ ํ์ฉํ์ฌ ๊ฐ๋ฐ ์ํฌํ๋ก์ฐ๋ฅผ ๊ฐ์ํํ๊ณ , ๋ณํํ๋ ์๊ตฌ ์ฌํญ์ ๋ฐ๋ผ ์ธํ๋ผ๋ฅผ ์ง์์ ์ผ๋ก ๊ฐ์ ํ์ธ์. ์น ๊ฐ๋ฐ ํ๊ฒฝ์ด ๊ณ์ ๋ฐ์ ํจ์ ๋ฐ๋ผ, ์ต์ ์น ์ปดํฌ๋ํธ ํ์ค ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ต์ ์ํ๋ก ์ ์งํ๋ ๊ฒ์ ์ ์ธ๊ณ ๊ณ ๊ฐ์ ๋์์ผ๋ก ํ๋ ํ๋์ ์ด๊ณ ๊ณ ํ์ง์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ํ์์ ์ ๋๋ค.